'''

Author      : jinas
E—mail      : jinasuo@163.com
Date        : 
Description :  CSDN人工智能培训班 卷集神经网络应用-- 图像相似图计算

'''

from __future__ import absolute_import,division,print_function  #python V2 V3 兼容处理

import base64
import os
import tarfile
import tempfile

import matplotlib.pyplot as plt
import numpy as np
import PIL
import tensorflow as tf
import tensorflow.contrib.slim as slim
import tensorflow.contrib.slim.nets as nets

from six.moves import urllib
from six.moves.urllib.request import urlretrieve


#设定一个缺省graph，将这之前的tensor或op清空
tf.reset_default_graph()
#设置log等级
tf.logging.set_verbosity(tf.logging.ERROR)
#初始化一个session
sess = tf.InteractiveSession()
#模型的输入
image = tf.Variable(tf.zeros((299,299,3)))

def network(image,reuse):
    '''
    获取由IMage图像集训练的inception-V3的模型以及输出
    :param image: 输入的图像
    :param reuse: 是否开启重使用
    :return: logits（未激活的输出），probs（softmax处理的数据），endpoints（网络模型各个层输出组成的字典）

    '''
    preprocessed = tf.multiply(tf.subtract(tf.expand_dims(image,0),0.5),2.0)
    arg_scope = nets.inception.inception_v3_arg_scope(weight_decay=0.0)
    #给 inception_V3 设置默认值
    with slim.arg_scope(arg_scope):
        logits,end_points = nets.inception.inception_v3(preprocessed,1001,is_training=False,
                                                        reuse=reuse)
        logits = logits[:,1:]
        probs = tf.nn.softmax(logits)
    return logits,probs,end_points


logits, probs, end_points = network(image,False)

#处理ckpt文件
data_dir = './'
checkpoint_filename = os.path.join(data_dir,'inception_v3.ckpt')
if not os.path.exists(checkpoint_filename):
    inception_tarball, _ = urlretrieve('http://download.tensorflow.org/models/inception_v3_2016_08_28.tar.gz')
    tarfile.open(inception_tarball,'r:gz').extract(data_dir)


#加载ckpt文件中参数的数值到本次session中
restore_vars = [
    var for var in tf.global_variables() if var.name.startswith('InceptionV3/')
]
saver = tf.train.Saver(restore_vars)
saver.restore(sess,os.path.join(data_dir,'inception_v3.ckpt'))

def get_features(img,feature_layer_name):
    p,feature_values = sess.run([probs,end_points],feed_dict={image:img})
    return feature_values[feature_layer_name].squeeze()

image_list=[
    'http://pic.zhutou.com/html/UploadPic/2010-6/2010664525773.jpg',
    #'http://pic.zhutou.com/html/UploadPic/2010-6/20106645315405.jpg',
    'http://img02.tooopen.com/Downs/images/2010/7/30/sy_20100730095430668065.jpg',
    'https://tse2-mm.cn.bing.net/th/id/OIP.f64kTGbkdfn5VqPX8iLvdgHaGz?pid=Api&rs=1',
    'http://www.ixiupet.com/uploads/allimg/160817/23104U531-1.jpg?imageView&thumbnail=500x0&quality=96&stripmeta=0&type=jpg',
    'http://www.ixiupet.com/uploads/allimg/160817/23104V535-2.jpg?imageView&thumbnail=500x0&quality=96&stripmeta=0&type=jpg',
    'http://pic32.photophoto.cn/20140706/0035035043964537_b.jpg',
    #'http://pic32.photophoto.cn/20140802/0035035079469488_b.jpg',
    'https://tse1-mm.cn.bing.net/th/id/OIP.QPV1iv8tIbCAb5NiSYnzVAHaGD?pid=Api&rs=1'

]

#图像的预处理
#包括 resize--统一处理输入图像的size
plt.figure(figsize=(12,12))
images = []
for idx,img_url in enumerate(image_list):
    img_path,_ = urlretrieve(img_url)
    img = PIL.Image.open(img_path)
    img = img.resize((299,299))

    plt.subplot(1,8,idx+1)
    plt.axis('off')
    plt.imshow(img)
    plt.title("image{}".format(idx))

    images.append(img)
plt.show()
layer = "PreLogits"   #分类层前一层的名称
features = []
#将像素转为0-1之间
#获取特定层的输出（分类层的前一层输出）
for img in images:
    img = (np.asarray(img) / 255.0).astype(np.float32)
    feature = get_features(img,layer)
    features.append(feature)

#这是输出结果，一行是一个数据，代表一个图片
feature_vectors = np.stack(features)

#验证书输出是否出错
score_feature_shape = 0
try:
    assert feature_vectors.shape == (7,2048),'shape mismatch!'
    score_feature_shape = 10
except Exception as ex:
    print(ex)

#计算特苏模式距离（不进行开方），浮点数在保存硬盘的时候特有问题精度问题
#每一行i代表一个样本
#每一列j表示距离j的距离长度
distance_euclidean = np.sum(
    np.power(feature_vectors,2),axis=1,keepdims=True) + np.sum(
    np.power(feature_vectors,2),axis=1,keepdims=True
).T - 2*np.dot(feature_vectors,feature_vectors.T)


features_norm = feature_vectors / np.linalg.norm(
    feature_vectors, axis=1)[:, np.newaxis]
distance_cosin = np.dot(features_norm, features_norm.T)

for idx_img, plt_img in enumerate(images):
    order_euclidean = np.argsort(distance_euclidean[idx_img])
    order_cosin = np.argsort(distance_cosin[idx_img])[::-1]

    plt.subplot(14, 8, idx_img * 8 * 2 + 1)
    plt.axis('off')
    plt.imshow(plt_img)

    for idx_sim, i in enumerate(order_euclidean):
        similay_img = images[i]
        plt.subplot(14, 8, idx_img * 8 * 2 + idx_sim + 2)
        plt.axis('off')
        plt.title('eucl-[{}]'.format(i))

        plt.imshow(similay_img)

    for idx_sim, i in enumerate(order_cosin):
        similay_img = images[i]
        plt.subplot(14, 8, 8 + (idx_img) * 8 * 2 + idx_sim + 2)
        plt.axis('off')
        plt.title('cos-[{}]'.format(i))

        plt.imshow(similay_img)

plt.show()


